<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    @keyframes FadeIn {
      from {
        opacity: 0;
        transform: translate(0, 50px);
      }

      to {
        opacity: 1;
        transform: translate(0, 0);
      }
    }

    * {
      margin: 0;
      padding: 0;
    }

    ul {
      position: relative;
      display: flex;
      flex-wrap: wrap;
    }

    li {
      position: absolute;
      background-color: lightgreen;
      width: 100px;
      list-style: none;
      box-sizing: border-box;
      display: none;
      opacity: .5;
      border-radius: 10px;
      animation: FadeIn 1s ease forwards;
      z-index: 0;
      /* transition: all .3s ease; */
    }

    li:hover {
      transform: scale(1.2) !important;
      transform-origin: center center;
      z-index: 1;
    }
  </style>
</head>

<body>
  <ul class="list"></ul>
  <script>

    // 列数
    const colNum = 9;
    // 列宽
    const colWidth = 100;
    // 每列高度
    const columns = [...Array(colNum)].fill(0);
    // 获取列表
    const list = document.querySelector('.list');

    /**
     * 延迟
     * @param {number} time 延迟时间，单位ms
     * @returns
     */
    function Sleep(time = 2000) {
      return new Promise(resolve => {
        setTimeout(() => {
          resolve(time);
        },
          time);
      });
    }

    /**
     * 获取元素高度
     * @param {HTMLElement} li
     * @returns
     */
    function GetLiHeight(li) {
      return Math.floor(li.getBoundingClientRect().height);
    }
    /**
     * 获取高度最小列的下标和高度
     * @param {number[]} arr
     * @returns
     */
    function GetMinHeightColumn() {
      let colIdx = 0;
      let colMinHeight = columns[0];

      for (let i = 0; i < columns.length; i++) {
        // 比较大小
        if (columns[i] < colMinHeight) {
          // 保存最小高度列的下标
          colIdx = i;
          // 保存列的最小高度
          colMinHeight = columns[i];
        }
      }
      return {
        colIdx,
        colMinHeight,
      };
    }

    /**
     * 生成li
     * @param {number} i
     * @returns
     */
    function GenerateLi(i) {
      // 找到高度最低列
      const colObj = GetMinHeightColumn();
      // 创建li
      const li = document.createElement('li');
      // 设置样式
      li.style.height = `${Math.floor(Math.random() * 200) + 50}px`;
      li.style.backgroundColor = `#${Math.floor(Math.random() * 16777216).toString(16)}`;
      li.style.display = 'block';
      // 设置位置
      li.style.left = i * colWidth + 'px';
      li.style.top = columns[i] + 'px';
      return li;
    }

    /**
     * 添加元素
     * @param {number} i
     */
    function AddItem(i) {
      if (list.children.length < colNum) {
        const li = GenerateLi(i);
        // 把li添加进列
        list.append(li);
        // 每列的第一个元素直接初始化每列的高度
        columns[i] = GetLiHeight(li);
      }
      else {
        // 获取最矮的列
        const minColObj = GetMinHeightColumn();
        // 创建元素放到最矮列尾
        const li = GenerateLi(minColObj.colIdx);
        list.append(li);
        // 更新最矮列高度
        columns[minColObj.colIdx] += GetLiHeight(li);
      }
    }

    /**
     * 入口函数
     */
    async function Entry() {
      for (let i = 0; i < 100; i++) {
        await Sleep(200);
        AddItem(i);
      }
    }
    Entry()

  </script>
</body>

</html>
